bitkeeper revision 1.1586 (4298e019QH28MgGwaw0jHPWEeEnyoA)
authorkaf24@firebug.cl.cam.ac.uk <kaf24@firebug.cl.cam.ac.uk>
Sat, 28 May 2005 21:18:17 +0000 (21:18 +0000)
committerkaf24@firebug.cl.cam.ac.uk <kaf24@firebug.cl.cam.ac.uk>
Sat, 28 May 2005 21:18:17 +0000 (21:18 +0000)
Clean up serial driver in Xen: separate ns16550 driver from generic
serial code.
Signed-off-by: Keir Fraser <keir@xensource.com>
12 files changed:
.rootkeys
xen/arch/ia64/xensetup.c
xen/arch/x86/cdb.c
xen/arch/x86/setup.c
xen/drivers/char/console.c
xen/drivers/char/ns16550.c [new file with mode: 0644]
xen/drivers/char/serial.c
xen/include/asm-ia64/config.h
xen/include/asm-ia64/serial.h
xen/include/asm-x86/serial.h [deleted file]
xen/include/xen/console.h
xen/include/xen/serial.h

index a8825238d665ef82836ba38d3c53284b833bd282..16e1ca03ab7ca8f7a1aacad8668fe0608e5644af 100644 (file)
--- a/.rootkeys
+++ b/.rootkeys
 40715b2cNVOegtvyft_AHFKJYRprfA xen/drivers/acpi/tables.c
 3e4a8cb7alzQCDKS7MlioPoHBKYkdQ xen/drivers/char/Makefile
 4049e6bfNSIq7s7OV-Bd69QD0RpR2Q xen/drivers/char/console.c
+4298e018XQtZkCdufpyFimOGZqqsFA xen/drivers/char/ns16550.c
 3e4a8cb7nMChlro4wvOBo76n__iCFA xen/drivers/char/serial.c
 40715b2cFpte_UNWnBZW0Du7z9AhTQ xen/include/acpi/acconfig.h
 40715b2ctNvVZ058w8eM8DR9hOat_A xen/include/acpi/acexcep.h
 3ddb79c2QF5-pZGzuX4QukPCDAl59A xen/include/asm-x86/processor.h
 40cf1596bim9F9DNdV75klgRSZ6Y2A xen/include/asm-x86/regs.h
 3ddb79c2plf7ciNgoNjU-RsbUzawsw xen/include/asm-x86/rwlock.h
-42136b49h6MkeayfuOaTPcJQWKga2g xen/include/asm-x86/serial.h
 405b8599BsDsDwKEJLS0XipaiQW3TA xen/include/asm-x86/shadow.h
 3ddb79c3Hgbb2g8CyWLMCK-6_ZVQSQ xen/include/asm-x86/smp.h
 3ddb79c3jn8ALV_S9W5aeTYUQRKBpg xen/include/asm-x86/smpboot.h
index ba6cd64f9482bfdb91751bcbea3e0640f6923654..f1f10a1f15fb2a0ed1fb1528ea08a41cbc56d8dd 100644 (file)
@@ -154,7 +154,8 @@ void start_kernel(void)
     early_setup_arch(&cmdline);
 
     /* We initialise the serial devices very early so we can get debugging. */
-    serial_init_stage1();
+    ns16550_init();
+    serial_init_preirq();
 
     init_console();
     set_printk_prefix("(XEN) ");
index f92e78f9c67de809dea8d33c620cb8d02e0d2a63..806b0c479e86a060d87479f405c9879d6123d177 100644 (file)
@@ -91,11 +91,11 @@ attempt_receive_packet(char *recv_buf, struct xendbg_context *ctx)
        u8 ch;
 
        /* Skip over everything up to the first '$' */
-       while ((ch = irq_serial_getc(ctx->serhnd)) != '$')
+       while ((ch = serial_getc(ctx->serhnd)) != '$')
                ;
        csum = 0;
        for (count = 0; count < 4096; count++) {
-               ch = irq_serial_getc(ctx->serhnd);
+               ch = serial_getc(ctx->serhnd);
                if (ch == '#')
                        break;
                recv_buf[count] = ch;
@@ -106,8 +106,8 @@ attempt_receive_packet(char *recv_buf, struct xendbg_context *ctx)
                return -1;
        }
        recv_buf[count] = 0;
-       received_csum = hex_char_val(irq_serial_getc(ctx->serhnd)) * 16 +
-               hex_char_val(irq_serial_getc(ctx->serhnd));
+       received_csum = hex_char_val(serial_getc(ctx->serhnd)) * 16 +
+               hex_char_val(serial_getc(ctx->serhnd));
        if (received_csum == csum) {
                return 0;
        } else {
@@ -163,7 +163,7 @@ xendbg_finish_reply(struct xendbg_context *ctx)
        xendbg_put_char('#', ctx);
        xendbg_send(buf, 2, ctx);
 
-       ch = irq_serial_getc(ctx->serhnd);
+       ch = serial_getc(ctx->serhnd);
        if (ch == '+')
                return 0;
        else
@@ -394,7 +394,7 @@ initialize_xendbg(void)
 {
        if (!strcmp(opt_cdb, "none"))
                return 0;
-       xdb_ctx.serhnd = parse_serial_handle(opt_cdb);
+       xdb_ctx.serhnd = serial_parse_handle(opt_cdb);
        if (xdb_ctx.serhnd == -1)
                panic("Can't parse %s as CDB serial info.\n", opt_cdb);
 
index 1a8ff629338f2ec6f9d6fe030c746713d4a80ca5..2d16e56a5289c31fec8b8d8aae0084d54d48887e 100644 (file)
@@ -216,7 +216,7 @@ static void __init start_of_day(void)
 
     initialize_keytable();
 
-    serial_init_stage2();
+    serial_init_postirq();
 
     init_xen_time();
 
@@ -263,7 +263,8 @@ void __init __start_xen(multiboot_info_t *mbi)
     smp_prepare_boot_cpu();
 
     /* We initialise the serial devices very early so we can get debugging. */
-    serial_init_stage1();
+    ns16550_init();
+    serial_init_preirq();
 
     init_console();
 
index b8e0f15fa462fc291361bf6bc07d6a4dfa9996ed..f588b5894523f9a95a042edf6698120c2218ac9f 100644 (file)
@@ -260,7 +260,7 @@ static void switch_serial_input(void)
     }
 }
 
-static void __serial_rx(unsigned char c, struct cpu_user_regs *regs)
+static void __serial_rx(char c, struct cpu_user_regs *regs)
 {
     if ( xen_rx )
         return handle_keypress(c, regs);
@@ -272,7 +272,7 @@ static void __serial_rx(unsigned char c, struct cpu_user_regs *regs)
     send_guest_virq(dom0->exec_domain[0], VIRQ_CONSOLE);
 }
 
-static void serial_rx(unsigned char c, struct cpu_user_regs *regs)
+static void serial_rx(char c, struct cpu_user_regs *regs)
 {
     static int switch_code_count = 0;
 
@@ -416,7 +416,7 @@ void init_console(void)
         if ( *p == ',' )
             p++;
         if ( strncmp(p, "com", 3) == 0 )
-            sercon_handle = parse_serial_handle(p);
+            sercon_handle = serial_parse_handle(p);
         else if ( strncmp(p, "vga", 3) == 0 )
             vgacon_enabled = 1;
     }
@@ -465,21 +465,6 @@ void console_force_lock(void)
     spin_lock(&console_lock);
 }
 
-void console_putc(char c)
-{
-    serial_putc(sercon_handle, c);
-}
-
-int console_getc(void)
-{
-    return serial_getc(sercon_handle);
-}
-
-int irq_console_getc(void)
-{
-    return irq_serial_getc(sercon_handle);
-}
-
 
 /*
  * **************************************************************
diff --git a/xen/drivers/char/ns16550.c b/xen/drivers/char/ns16550.c
new file mode 100644 (file)
index 0000000..89e6449
--- /dev/null
@@ -0,0 +1,263 @@
+/******************************************************************************
+ * ns16550.c
+ * 
+ * Driver for 16550-series UARTs. This driver is to be kept within Xen as
+ * it permits debugging of seriously-toasted machines (e.g., in situations
+ * where a device driver within a guest OS would be inaccessible).
+ * 
+ * Copyright (c) 2003-2005, K A Fraser
+ */
+
+#include <xen/config.h>
+#include <xen/init.h>
+#include <xen/irq.h>
+#include <xen/sched.h>
+#include <xen/serial.h>
+#include <asm/io.h>
+
+/* Config serial port with a string <baud>,DPS,<io-base>,<irq>. */
+static char opt_com1[30] = "", opt_com2[30] = "";
+string_param("com1", opt_com1);
+string_param("com2", opt_com2);
+
+static struct ns16550 {
+    int baud, data_bits, parity, stop_bits, io_base, irq;
+    struct irqaction irqaction;
+} ns16550_com[2] = {
+    { 0, 0, 0, 0, 0x3f8, 4 },
+    { 0, 0, 0, 0, 0x2f8, 3 }
+};
+
+/* Register offsets */
+#define RBR             0x00    /* receive buffer       */
+#define THR             0x00    /* transmit holding     */
+#define IER             0x01    /* interrupt enable     */
+#define IIR             0x02    /* interrupt identity   */
+#define FCR             0x02    /* FIFO control         */
+#define LCR             0x03    /* line control         */
+#define MCR             0x04    /* Modem control        */
+#define LSR             0x05    /* line status          */
+#define MSR             0x06    /* Modem status         */
+#define DLL             0x00    /* divisor latch (ls) (DLAB=1) */
+#define DLM             0x01    /* divisor latch (ms) (DLAB=1) */
+
+/* Interrupt Enable Register */
+#define IER_ERDAI       0x01    /* rx data recv'd       */
+#define IER_ETHREI      0x02    /* tx reg. empty        */
+#define IER_ELSI        0x04    /* rx line status       */
+#define IER_EMSI        0x08    /* MODEM status         */
+
+/* FIFO control register */
+#define FCR_ENABLE      0x01    /* enable FIFO          */
+#define FCR_CLRX        0x02    /* clear Rx FIFO        */
+#define FCR_CLTX        0x04    /* clear Tx FIFO        */
+#define FCR_DMA         0x10    /* enter DMA mode       */
+#define FCR_TRG1        0x00    /* Rx FIFO trig lev 1   */
+#define FCR_TRG4        0x40    /* Rx FIFO trig lev 4   */
+#define FCR_TRG8        0x80    /* Rx FIFO trig lev 8   */
+#define FCR_TRG14       0xc0    /* Rx FIFO trig lev 14  */
+
+/* Line control register */
+#define LCR_DLAB        0x80    /* Divisor Latch Access */
+
+/* Modem Control Register */
+#define MCR_DTR         0x01    /* Data Terminal Ready  */
+#define MCR_RTS         0x02    /* Request to Send      */
+#define MCR_OUT2        0x08    /* OUT2: interrupt mask */
+
+/* Line Status Register */
+#define LSR_DR          0x01    /* Data ready           */
+#define LSR_OE          0x02    /* Overrun              */
+#define LSR_PE          0x04    /* Parity error         */
+#define LSR_FE          0x08    /* Framing error        */
+#define LSR_BI          0x10    /* Break                */
+#define LSR_THRE        0x20    /* Xmit hold reg empty  */
+#define LSR_TEMT        0x40    /* Xmitter empty        */
+#define LSR_ERR         0x80    /* Error                */
+
+/* These parity settings can be ORed directly into the LCR. */
+#define PARITY_NONE     (0<<3)
+#define PARITY_ODD      (1<<3)
+#define PARITY_EVEN     (3<<3)
+#define PARITY_MARK     (5<<3)
+#define PARITY_SPACE    (7<<3)
+
+static void ns16550_interrupt(
+    int irq, void *dev_id, struct cpu_user_regs *regs)
+{
+    serial_rx_interrupt(dev_id, regs);
+}
+
+static void ns16550_putc(struct serial_port *port, char c)
+{
+    struct ns16550 *uart = port->uart;
+
+    while ( !(inb(uart->io_base + LSR) & LSR_THRE) )
+        cpu_relax();
+
+    outb(c, uart->io_base + THR);
+}
+
+static int ns16550_getc(struct serial_port *port, char *pc)
+{
+    struct ns16550 *uart = port->uart;
+
+    if ( !(inb(uart->io_base + LSR) & LSR_DR) )
+        return 0;
+
+    *pc = inb(uart->io_base + RBR);
+    return 1;
+}
+
+static void ns16550_init_preirq(struct serial_port *port)
+{
+    struct ns16550 *uart = port->uart;
+    unsigned char lcr;
+
+    lcr = (uart->data_bits - 5) | ((uart->stop_bits - 1) << 2) | uart->parity;
+
+    /* No interrupts. */
+    outb(0, uart->io_base + IER);
+
+    /* Line control and baud-rate generator. */
+    outb(lcr | LCR_DLAB,    uart->io_base + LCR);
+    outb(115200/uart->baud, uart->io_base + DLL); /* baud lo */
+    outb(0,                 uart->io_base + DLM); /* baud hi */
+    outb(lcr,               uart->io_base + LCR); /* parity, data, stop */
+
+    /* No flow ctrl: DTR and RTS are both wedged high to keep remote happy. */
+    outb(MCR_DTR | MCR_RTS, uart->io_base + MCR);
+
+    /* Enable and clear the FIFOs. Set a large trigger threshold. */
+    outb(FCR_ENABLE | FCR_CLRX | FCR_CLTX | FCR_TRG14, uart->io_base + FCR);
+}
+
+static void ns16550_init_postirq(struct serial_port *port)
+{
+    struct ns16550 *uart = port->uart;
+    int rc;
+
+    uart->irqaction.handler = ns16550_interrupt;
+    uart->irqaction.name    = "ns16550";
+    uart->irqaction.dev_id  = port;
+    if ( (rc = setup_irq(uart->irq, &uart->irqaction)) != 0 )
+        printk("ERROR: Failed to allocate na16550 IRQ %d\n", uart->irq);
+
+    /* For sanity, clear the receive FIFO. */
+    outb(FCR_ENABLE | FCR_CLRX | FCR_TRG14, uart->io_base + FCR);
+
+    /* Master interrupt enable; also keep DTR/RTS asserted. */
+    outb(MCR_OUT2 | MCR_DTR | MCR_RTS, uart->io_base + MCR);
+
+    /* Enable receive interrupts. */
+    outb(IER_ERDAI, uart->io_base + IER);
+}
+
+#ifdef CONFIG_X86
+#include <asm/physdev.h>
+static void ns16550_endboot(struct serial_port *port)
+{
+    struct ns16550 *uart = port->uart;
+    physdev_modify_ioport_access_range(dom0, 0, uart->io_base, 8);
+}
+#else
+#define ns16550_endboot NULL
+#endif
+
+static struct uart_driver ns16550_driver = {
+    .init_preirq  = ns16550_init_preirq,
+    .init_postirq = ns16550_init_postirq,
+    .endboot      = ns16550_endboot,
+    .putc         = ns16550_putc,
+    .getc         = ns16550_getc
+};
+
+#define PARSE_ERR(_f, _a...)                 \
+    do {                                     \
+        printk( "ERROR: " _f "\n" , ## _a ); \
+        return;                              \
+    } while ( 0 )
+
+static void ns16550_parse_port_config(struct ns16550 *uart, char *conf)
+{
+    if ( *conf == '\0' )
+        return;
+
+    uart->baud = simple_strtol(conf, &conf, 10);
+    if ( (uart->baud < 1200) || (uart->baud > 115200) )
+        PARSE_ERR("Baud rate %d outside supported range.", uart->baud);
+
+    if ( *conf != ',' )
+        PARSE_ERR("Missing data/parity/stop specifiers.");
+
+    conf++;
+
+    uart->data_bits = simple_strtol(conf, &conf, 10);
+    if ( (uart->data_bits < 5) || (uart->data_bits > 8) )
+        PARSE_ERR("%d data bits are unsupported.", uart->data_bits);
+
+    switch ( *conf )
+    {
+    case 'n':
+        uart->parity = PARITY_NONE;
+        break;
+    case 'o': 
+        uart->parity =  PARITY_ODD;
+        break;
+    case 'e': 
+        uart->parity =  PARITY_EVEN;
+        break;
+    case 'm': 
+        uart->parity =  PARITY_MARK;
+        break;
+    case 's': 
+        uart->parity =  PARITY_SPACE;
+        break;
+
+    default:
+        PARSE_ERR("Invalid parity specifier '%c'.", *conf);
+    }
+
+    conf++;
+
+    uart->stop_bits = simple_strtol(conf, &conf, 10);
+    if ( (uart->stop_bits < 1) || (uart->stop_bits > 2) )
+        PARSE_ERR("%d stop bits are unsupported.", uart->stop_bits);
+
+    if ( *conf == ',' )
+    {
+        conf++;
+
+        uart->io_base = simple_strtol(conf, &conf, 0);
+        if ( (uart->io_base <= 0x0000) || (uart->io_base > 0xfff0) )
+            PARSE_ERR("I/O port base 0x%x is outside the supported range.",
+                      uart->io_base);
+
+        if ( *conf != ',' )
+            PARSE_ERR("Missing IRQ specifier.");
+            
+        conf++;
+            
+        uart->irq = simple_strtol(conf, &conf, 10);
+        if ( (uart->irq <= 0) || (uart->irq >= 32) )
+            PARSE_ERR("IRQ %d is outside the supported range.", uart->irq);
+    }
+
+    serial_register_uart(uart - ns16550_com, &ns16550_driver, uart);
+}
+
+void ns16550_init(void)
+{
+    ns16550_parse_port_config(&ns16550_com[0], opt_com1);
+    ns16550_parse_port_config(&ns16550_com[1], opt_com2);
+}
+
+/*
+ * Local variables:
+ * mode: C
+ * c-set-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
index 7d9852ebabd92049c1dab9e866d1c0bfc7e299f1..c578de152c043ff0af9ada1dc424bef3d2876c84 100644 (file)
@@ -1,9 +1,7 @@
 /******************************************************************************
  * serial.c
  * 
- * Driver for 16550-series UARTs. This driver is to be kept within Xen as
- * it permits debugging of seriously-toasted machines (e.g., in situations
- * where a device driver within a guest OS would be inaccessible).
+ * Framework for serial device drivers.
  * 
  * Copyright (c) 2003-2005, K A Fraser
  */
 #include <xen/reboot.h>
 #include <xen/sched.h>
 #include <xen/serial.h>
-#include <asm/io.h>
-
-#ifdef CONFIG_X86
-#include <asm/physdev.h>
-#endif
-
-/* Config serial port with a string <baud>,DPS,<io-base>,<irq>. */
-static char opt_com1[30] = OPT_COM1_STR, opt_com2[30] = OPT_COM2_STR;
-string_param("com1", opt_com1);
-string_param("com2", opt_com2);
-
-static struct uart com[2] = {
-    { 0, 0, 0, 0, 0x3f8, 4,
-      NULL, NULL, NULL,
-      SPIN_LOCK_UNLOCKED },
-    { 0, 0, 0, 0, 0x2f8, 3,
-      NULL, NULL, NULL,
-      SPIN_LOCK_UNLOCKED }
-};
-
-#define UART_ENABLED(_u) ((_u)->baud != 0)
-#define DISABLE_UART(_u) ((_u)->baud = 0)
-
 
-/***********************
- * PRIVATE FUNCTIONS
- */
+static struct serial_port com[2] = {
+    { .lock = SPIN_LOCK_UNLOCKED }, 
+    { .lock = SPIN_LOCK_UNLOCKED }
+};
 
-static void uart_rx(struct uart *uart, struct cpu_user_regs *regs)
+void serial_rx_interrupt(struct serial_port *port, struct cpu_user_regs *regs)
 {
-    unsigned char c;
+    char c;
+    serial_rx_fn fn;
+    unsigned long flags;
 
-    if ( !UART_ENABLED(uart) )
-        return;
+    BUG_ON(!port->driver);
+    BUG_ON(!port->driver->getc);
 
-    /*
-     * No need for the uart spinlock here. Only the uart's own interrupt
-     * handler will read from the RBR and the handler isn't reentrant.
-     * Calls to serial_getc() will disable this handler before proceeding.
-     */
-    while ( inb(uart->io_base + LSR) & LSR_DR )
+    spin_lock_irqsave(&port->lock, flags);
+
+    while ( port->driver->getc(port, &c) )
     {
-        c = inb(uart->io_base + RBR);
-        if ( uart->rx != NULL )
-            uart->rx(c, regs);
-        else if ( (c & 0x80) && (uart->rx_hi != NULL) )
-            uart->rx_hi(c&0x7f, regs);
-        else if ( !(c & 0x80) && (uart->rx_lo != NULL) )
-            uart->rx_lo(c&0x7f, regs);
-        else if ( (uart->rxbufp - uart->rxbufc) != RXBUFSZ )
-            uart->rxbuf[MASK_RXBUF_IDX(uart->rxbufp++)] = c;            
+        fn = NULL;
+
+        if ( port->rx != NULL )
+            fn = port->rx;
+        else if ( (c & 0x80) && (port->rx_hi != NULL) )
+            fn = port->rx_hi;
+        else if ( !(c & 0x80) && (port->rx_lo != NULL) )
+            fn = port->rx_lo;
+        else if ( (port->rxbufp - port->rxbufc) != RXBUFSZ )
+            port->rxbuf[MASK_RXBUF_IDX(port->rxbufp++)] = c;            
+
+        if ( fn != NULL )
+        {
+            spin_unlock_irqrestore(&port->lock, flags);
+            (*fn)(c & 0x7f, regs);
+            spin_lock_irqsave(&port->lock, flags);
+        }
     }
-}
 
-static void serial_interrupt(
-    int irq, void *dev_id, struct cpu_user_regs *regs)
-{
-    uart_rx((struct uart *)dev_id, regs);
+    spin_unlock_irqrestore(&port->lock, flags);
 }
 
-static inline void __serial_putc(
-    struct uart *uart, int handle, unsigned char c)
+void serial_putc(int handle, char c)
 {
+    struct serial_port *port = &com[handle & SERHND_IDX];
     unsigned long flags;
-    int space;
+
+    if ( (handle == -1) || !port->driver || !port->driver->putc )
+        return;
+
+    spin_lock_irqsave(&port->lock, flags);
 
     if ( (c == '\n') && (handle & SERHND_COOKED) )
-        __serial_putc(uart, handle, '\r');
+        port->driver->putc(port, '\r');
 
     if ( handle & SERHND_HI )
         c |= 0x80;
     else if ( handle & SERHND_LO )
         c &= 0x7f;
 
-    do { 
-        spin_lock_irqsave(&uart->lock, flags);
-        space = arch_serial_putc(uart, c);
-        spin_unlock_irqrestore(&uart->lock, flags);
-    }
-    while ( !space );
+    port->driver->putc(port, c);
+
+    spin_unlock_irqrestore(&port->lock, flags);
 }
 
-#define PARSE_ERR(_f, _a...)                 \
-    do {                                     \
-        printk( "ERROR: " _f "\n" , ## _a ); \
-        DISABLE_UART(uart);                  \
-        return;                              \
-} while ( 0 )
-        
-static void parse_port_config(char *conf, struct uart *uart)
+void serial_puts(int handle, const char *s)
 {
-    if ( *conf == '\0' )
-        return;
-
-    uart->baud = simple_strtol(conf, &conf, 10);
-    if ( (uart->baud < 1200) || (uart->baud > 115200) )
-        PARSE_ERR("Baud rate %d outside supported range.", uart->baud);
-
-    if ( *conf != ',' )
-        PARSE_ERR("Missing data/parity/stop specifiers.");
-
-    conf++;
-
-    uart->data_bits = simple_strtol(conf, &conf, 10);
-    if ( (uart->data_bits < 5) || (uart->data_bits > 8) )
-        PARSE_ERR("%d data bits are unsupported.", uart->data_bits);
+    while ( *s != '\0' )
+        serial_putc(handle, *s++);
+}
 
-    switch ( *conf )
+/* Returns TRUE if given character (*pc) matches the serial handle. */
+static int byte_matches(int handle, unsigned char *pc)
+{
+    if ( !(handle & SERHND_HI) )
     {
-    case 'n':
-        uart->parity = PARITY_NONE;
-        break;
-    case 'o': 
-        uart->parity =  PARITY_ODD;
-        break;
-    case 'e': 
-        uart->parity =  PARITY_EVEN;
-        break;
-    case 'm': 
-        uart->parity =  PARITY_MARK;
-        break;
-    case 's': 
-        uart->parity =  PARITY_SPACE;
-        break;
-
-    default:
-        PARSE_ERR("Invalid parity specifier '%c'.", *conf);
+        if ( !(handle & SERHND_LO) || !(*pc & 0x80) )
+            return 1;
     }
-
-    conf++;
-
-    uart->stop_bits = simple_strtol(conf, &conf, 10);
-    if ( (uart->stop_bits < 1) || (uart->stop_bits > 2) )
-        PARSE_ERR("%d stop bits are unsupported.", uart->stop_bits);
-
-    if ( *conf == ',' )
+    else if ( *pc & 0x80 )
     {
-        conf++;
-
-        uart->io_base = simple_strtol(conf, &conf, 0);
-        if ( (uart->io_base <= 0x0000) || (uart->io_base > 0xfff0) )
-            PARSE_ERR("I/O port base 0x%x is outside the supported range.",
-                      uart->io_base);
-
-        if ( *conf != ',' )
-            PARSE_ERR("Missing IRQ specifier.");
-            
-        conf++;
-            
-        uart->irq = simple_strtol(conf, &conf, 10);
-        if ( (uart->irq <= 0) || (uart->irq >= 32) )
-            PARSE_ERR("IRQ %d is outside the supported range.", uart->irq);
+        *pc &= 0x7f;
+        return 1;
     }
+    return 0;
 }
 
-static void uart_config_stage1(struct uart *uart)
-{
-    unsigned char lcr;
-
-    if ( !UART_ENABLED(uart) )
-        return;
-
-    lcr = (uart->data_bits - 5) | ((uart->stop_bits - 1) << 2) | uart->parity;
-
-    /* No interrupts. */
-    outb(0, uart->io_base + IER);
-
-    /* Line control and baud-rate generator. */
-    outb(lcr | LCR_DLAB,    uart->io_base + LCR);
-    outb(115200/uart->baud, uart->io_base + DLL); /* baud lo */
-    outb(0,                 uart->io_base + DLM); /* baud hi */
-    outb(lcr,               uart->io_base + LCR); /* parity, data, stop */
-
-    /* No flow ctrl: DTR and RTS are both wedged high to keep remote happy. */
-    outb(MCR_DTR | MCR_RTS, uart->io_base + MCR);
-
-    /* Enable and clear the FIFOs. Set a large trigger threshold. */
-    outb(FCR_ENABLE | FCR_CLRX | FCR_CLTX | FCR_TRG14, uart->io_base + FCR);
-}
-
-static void uart_config_stage2(struct uart *uart)
+char serial_getc(int handle)
 {
-    int rc;
-
-    if ( !UART_ENABLED(uart) )
-        return;
-
-    uart->irqaction.handler = serial_interrupt;
-    uart->irqaction.name    = "serial";
-    uart->irqaction.dev_id  = uart;
-    if ( (rc = setup_irq(uart->irq, &uart->irqaction)) != 0 )
-        printk("ERROR: Failed to allocate serial IRQ %d\n", uart->irq);
-
-    /* For sanity, clear the receive FIFO. */
-    outb(FCR_ENABLE | FCR_CLRX | FCR_TRG14, uart->io_base + FCR);
-
-    /* Master interrupt enable; also keep DTR/RTS asserted. */
-    outb(MCR_OUT2 | MCR_DTR | MCR_RTS, uart->io_base + MCR);
-
-    /* Enable receive interrupts. */
-    outb(IER_ERDAI, uart->io_base + IER);
-}
-
+    struct serial_port *port = &com[handle & SERHND_IDX];
+    unsigned char c;
+    unsigned long flags;
 
-/***********************
- * PUBLIC FUNCTIONS
- */
+    if ( (handle == -1) || !port->driver || !port->driver->getc )
+        return '\0';
 
-void serial_init_stage1(void)
-{
-    parse_port_config(opt_com1, &com[0]);
-    parse_port_config(opt_com2, &com[1]);
+    spin_lock_irqsave(&port->lock, flags);
 
-    uart_config_stage1(&com[0]);
-    uart_config_stage1(&com[1]);
-}
+    while ( port->rxbufp != port->rxbufc )
+    {
+        c = port->rxbuf[MASK_RXBUF_IDX(port->rxbufc++)];
+        if ( byte_matches(handle, &c) )
+            goto out;
+    }
+    
+    while ( !port->driver->getc(port, &c) && !byte_matches(handle, &c) )
+        continue;
 
-void serial_init_stage2(void)
-{
-    uart_config_stage2(&com[0]);
-    uart_config_stage2(&com[1]);
+ out:
+    spin_unlock_irqrestore(&port->lock, flags);
+    return c;
 }
 
-int parse_serial_handle(char *conf)
+int serial_parse_handle(char *conf)
 {
     int handle;
 
@@ -261,14 +148,6 @@ int parse_serial_handle(char *conf)
         goto fail;
     }
 
-#ifndef NO_UART_CONFIG_OK
-    if ( !UART_ENABLED(&com[handle]) )
-    {
-        printk("ERROR: cannot use unconfigured serial port COM%d\n", handle+1);
-        return -1;
-    }
-#endif
-
     if ( conf[4] == 'H' )
         handle |= SERHND_HI;
     else if ( conf[4] == 'L' )
@@ -285,147 +164,80 @@ int parse_serial_handle(char *conf)
 
 void serial_set_rx_handler(int handle, serial_rx_fn fn)
 {
-    struct uart *uart = &com[handle & SERHND_IDX];
+    struct serial_port *port = &com[handle & SERHND_IDX];
     unsigned long flags;
 
     if ( handle == -1 )
         return;
 
-    spin_lock_irqsave(&uart->lock, flags);
+    spin_lock_irqsave(&port->lock, flags);
 
-    if ( uart->rx != NULL )
+    if ( port->rx != NULL )
         goto fail;
 
     if ( handle & SERHND_LO )
     {
-        if ( uart->rx_lo != NULL )
+        if ( port->rx_lo != NULL )
             goto fail;
-        uart->rx_lo = fn;        
+        port->rx_lo = fn;        
     }
     else if ( handle & SERHND_HI )
     {
-        if ( uart->rx_hi != NULL )
+        if ( port->rx_hi != NULL )
             goto fail;
-        uart->rx_hi = fn;
+        port->rx_hi = fn;
     }
     else
     {
-        if ( (uart->rx_hi != NULL) || (uart->rx_lo != NULL) )
+        if ( (port->rx_hi != NULL) || (port->rx_lo != NULL) )
             goto fail;
-        uart->rx = fn;
+        port->rx = fn;
     }
 
-    spin_unlock_irqrestore(&uart->lock, flags);
+    spin_unlock_irqrestore(&port->lock, flags);
     return;
 
  fail:
-    spin_unlock_irqrestore(&uart->lock, flags);
+    spin_unlock_irqrestore(&port->lock, flags);
     printk("ERROR: Conflicting receive handlers for COM%d\n", 
            handle & SERHND_IDX);
 }
 
-void serial_putc(int handle, unsigned char c)
-{
-    struct uart *uart = &com[handle & SERHND_IDX];
-
-    if ( handle == -1 )
-        return;
-
-    __serial_putc(uart, handle, c);
-}
-
-void serial_puts(int handle, const char *s)
-{
-    struct uart *uart = &com[handle & SERHND_IDX];
-
-    if ( handle == -1 )
-        return;
-
-    while ( *s != '\0' )
-        __serial_putc(uart, handle, *s++);
-}
-
-/* Returns TRUE if given character (*pc) matches the serial handle. */
-static int byte_matches(int handle, unsigned char *pc)
-{
-    if ( !(handle & SERHND_HI) )
-    {
-        if ( !(handle & SERHND_LO) || !(*pc & 0x80) )
-            return 1;
-    }
-    else if ( *pc & 0x80 )
-    {
-        *pc &= 0x7f;
-        return 1;
-    }
-    return 0;
-}
-
-unsigned char irq_serial_getc(int handle)
+void serial_force_unlock(int handle)
 {
-    struct uart *uart = &com[handle & SERHND_IDX];
-    unsigned char c;
-
-
-    while ( uart->rxbufp != uart->rxbufc )
-    {
-        c = uart->rxbuf[MASK_RXBUF_IDX(uart->rxbufc++)];
-        if ( byte_matches(handle, &c) )
-            goto out;
-    }
-    
-    /* We now wait for the UART to receive a suitable character. */
-    do {
-        while ( (inb(uart->io_base + LSR) & LSR_DR) == 0 )
-            barrier();
-        c = inb(uart->io_base + RBR);
-    }
-    while ( !byte_matches(handle, &c) );
-    
- out:
-    return c;
+    struct serial_port *port = &com[handle & SERHND_IDX];
+    if ( handle != -1 )
+        port->lock = SPIN_LOCK_UNLOCKED;
 }
 
-unsigned char serial_getc(int handle)
+void serial_init_preirq(void)
 {
-    struct uart *uart = &com[handle & SERHND_IDX];
-    unsigned char c;
-    unsigned long flags;
-
-    spin_lock_irqsave(&uart->lock, flags);
-
-    while ( uart->rxbufp != uart->rxbufc )
-    {
-        c = uart->rxbuf[MASK_RXBUF_IDX(uart->rxbufc++)];
-        if ( byte_matches(handle, &c) )
-            goto out;
-    }
-    
-    disable_irq(uart->irq);
-
-    c = irq_serial_getc(handle);
-    
-    enable_irq(uart->irq);
- out:
-    spin_unlock_irqrestore(&uart->lock, flags);
-    return c;
+    int i;
+    for ( i = 0; i < ARRAY_SIZE(com); i++ )
+        if ( com[i].driver && com[i].driver->init_preirq )
+            com[i].driver->init_preirq(&com[i]);
 }
 
-void serial_force_unlock(int handle)
+void serial_init_postirq(void)
 {
-    struct uart *uart = &com[handle & SERHND_IDX];
-    if ( handle != -1 )
-        uart->lock = SPIN_LOCK_UNLOCKED;
+    int i;
+    for ( i = 0; i < ARRAY_SIZE(com); i++ )
+        if ( com[i].driver && com[i].driver->init_postirq )
+            com[i].driver->init_postirq(&com[i]);
 }
 
 void serial_endboot(void)
 {
-#ifdef CONFIG_X86
     int i;
     for ( i = 0; i < ARRAY_SIZE(com); i++ )
-        if ( UART_ENABLED(&com[i]) )
-            physdev_modify_ioport_access_range(dom0, 0, com[i].io_base, 8);
-#endif
+        if ( com[i].driver && com[i].driver->endboot )
+            com[i].driver->endboot(&com[i]);
+}
+
+void serial_register_uart(int idx, struct uart_driver *driver, void *uart)
+{
+    com[idx].driver = driver;
+    com[idx].uart   = uart;
 }
 
 /*
index bb7e5f6e16d5db164841f900b87cebbc31e1803f..34603f5418bbbd053dbe3eee59213c065c1ed8a6 100644 (file)
@@ -160,9 +160,6 @@ void sort_main_extable(void);
     (likely(sizeof(count) <= 4) /* disallow 64-bit counts */ &&  \
      access_ok(type,addr,count*size))
 
-// without this, uart_config_stageX does outb's which are non-portable
-#define NO_UART_CONFIG_OK
-
 // see drivers/char/console.c
 #ifndef CONFIG_VTI
 #define        OPT_CONSOLE_STR "com1"
index faeaf526e8ac0912a0bc137a5806cb6e4aa3e67b..4acf7a77f1418bb93cc4f87f320cd2ea8ec6f495 100644 (file)
 #define arch_serial_putc(_uart, _c)                                    \
        ( platform_is_hp_ski() ? (ia64_ssc(c,0,0,0,SSC_PUTCHAR), 1) :   \
        ( longs_peak_putc(c), 1 ))
-
-#define OPT_COM1_STR "115200"
-#define OPT_COM2_STR ""
-#else // CONFIG_VTI
+#else
 #define arch_serial_putc(_uart, _c)                                    \
        ( platform_is_hp_ski() ? (ia64_ssc(c,0,0,0,SSC_PUTCHAR), 1) :   \
        ( (inb((_uart)->io_base + LSR) & LSR_THRE) ?                    \
        (outb((_c), (_uart)->io_base + THR), 1) : 0 ))
-
-#define OPT_COM1_STR ""
-#define OPT_COM2_STR "57600,8n1"
-#endif // CONFIG_VTI
-
-unsigned char irq_serial_getc(int handle);
-
-void serial_force_unlock(int handle);
+#endif
 
 #endif /* __ASM_SERIAL_H__ */
diff --git a/xen/include/asm-x86/serial.h b/xen/include/asm-x86/serial.h
deleted file mode 100644 (file)
index b93d28f..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-
-#ifndef __ASM_X86_SERIAL_H__
-#define __ASM_X86_SERIAL_H__
-
-#define OPT_COM1_STR ""
-#define OPT_COM2_STR ""
-
-#define arch_serial_putc(_uart, _c)                 \
-    ( (inb((_uart)->io_base + LSR) & LSR_THRE) ?    \
-      (outb((_c), (_uart)->io_base + THR), 1) : 0 )
-
-#endif /* __ASM_X86_SERIAL_H__ */
-
-/*
- * Local variables:
- * mode: C
- * c-set-style: "BSD"
- * c-basic-offset: 4
- * tab-width: 4
- * indent-tabs-mode: nil
- * End:
- */
index f65633a1af22c9eecf141604b63f722c8eab6d98..024840c0addec83513bed6876bad1feb7bbdca68 100644 (file)
@@ -22,8 +22,4 @@ void console_endboot(int disable_vga);
 void console_force_unlock(void);
 void console_force_lock(void);
 
-void console_putc(char c);
-int console_getc(void);
-int irq_console_getc(void);
-
 #endif /* __CONSOLE_H__ */
index 51a0d1a1f2abe64da33845e923386b7d1489ce20..73daa385f0bbe1029b9d2e295b874d05a15a2085 100644 (file)
@@ -1,9 +1,7 @@
 /******************************************************************************
  * serial.h
  * 
- * Driver for 16550-series UARTs. This driver is to be kept within Xen as
- * it permits debugging of seriously-toasted machines (e.g., in situations
- * where a device driver within a guest OS would be inaccessible).
+ * Framework for serial device drivers.
  * 
  * Copyright (c) 2003-2005, K A Fraser
  */
 #ifndef __XEN_SERIAL_H__
 #define __XEN_SERIAL_H__
 
-#include <xen/irq.h>
-#include <asm/regs.h>
-#include <asm/serial.h>
-
-/* Register offsets */
-#define RBR             0x00    /* receive buffer       */
-#define THR             0x00    /* transmit holding     */
-#define IER             0x01    /* interrupt enable     */
-#define IIR             0x02    /* interrupt identity   */
-#define FCR             0x02    /* FIFO control         */
-#define LCR             0x03    /* line control         */
-#define MCR             0x04    /* Modem control        */
-#define LSR             0x05    /* line status          */
-#define MSR             0x06    /* Modem status         */
-#define DLL             0x00    /* divisor latch (ls) (DLAB=1) */
-#define DLM             0x01    /* divisor latch (ms) (DLAB=1) */
-
-/* Interrupt Enable Register */
-#define IER_ERDAI       0x01    /* rx data recv'd       */
-#define IER_ETHREI      0x02    /* tx reg. empty        */
-#define IER_ELSI        0x04    /* rx line status       */
-#define IER_EMSI        0x08    /* MODEM status         */
-
-/* FIFO control register */
-#define FCR_ENABLE      0x01    /* enable FIFO          */
-#define FCR_CLRX        0x02    /* clear Rx FIFO        */
-#define FCR_CLTX        0x04    /* clear Tx FIFO        */
-#define FCR_DMA         0x10    /* enter DMA mode       */
-#define FCR_TRG1        0x00    /* Rx FIFO trig lev 1   */
-#define FCR_TRG4        0x40    /* Rx FIFO trig lev 4   */
-#define FCR_TRG8        0x80    /* Rx FIFO trig lev 8   */
-#define FCR_TRG14       0xc0    /* Rx FIFO trig lev 14  */
-
-/* Line control register */
-#define LCR_DLAB        0x80    /* Divisor Latch Access */
-
-/* Modem Control Register */
-#define MCR_DTR         0x01    /* Data Terminal Ready  */
-#define MCR_RTS         0x02    /* Request to Send      */
-#define MCR_OUT2        0x08    /* OUT2: interrupt mask */
-
-/* Line Status Register */
-#define LSR_DR          0x01    /* Data ready           */
-#define LSR_OE          0x02    /* Overrun              */
-#define LSR_PE          0x04    /* Parity error         */
-#define LSR_FE          0x08    /* Framing error        */
-#define LSR_BI          0x10    /* Break                */
-#define LSR_THRE        0x20    /* Xmit hold reg empty  */
-#define LSR_TEMT        0x40    /* Xmitter empty        */
-#define LSR_ERR         0x80    /* Error                */
-
-/* These parity settings can be ORed directly into the LCR. */
-#define PARITY_NONE     (0<<3)
-#define PARITY_ODD      (1<<3)
-#define PARITY_EVEN     (3<<3)
-#define PARITY_MARK     (5<<3)
-#define PARITY_SPACE    (7<<3)
+struct cpu_user_regs;
 
 /* Register a character-receive hook on the specified COM port. */
-typedef void (*serial_rx_fn)(unsigned char, struct cpu_user_regs *);
+typedef void (*serial_rx_fn)(char, struct cpu_user_regs *);
 void serial_set_rx_handler(int handle, serial_rx_fn fn);
 
+/* Number of characters we buffer for a polling receiver. */
 #define RXBUFSZ 32
 #define MASK_RXBUF_IDX(_i) ((_i)&(RXBUFSZ-1))
-struct uart {
-    int              baud, data_bits, parity, stop_bits, io_base, irq;
-    serial_rx_fn     rx_lo, rx_hi, rx;
-    spinlock_t       lock;
-    unsigned char    rxbuf[RXBUFSZ];
-    unsigned int     rxbufp, rxbufc;
-    struct irqaction irqaction;
+
+struct uart_driver;
+
+struct serial_port {
+    /* Uart-driver parameters. */
+    struct uart_driver *driver;
+    void               *uart;
+    /* Receiver callback functions (asynchronous receivers). */
+    serial_rx_fn        rx_lo, rx_hi, rx;
+    /* Receive data buffer (polling receivers). */
+    char                rxbuf[RXBUFSZ];
+    unsigned int        rxbufp, rxbufc;
+    /* Serial I/O is concurrency-safe. */
+    spinlock_t          lock;
+};
+
+struct uart_driver {
+    /* Driver initialisation (pre- and post-IRQ subsystem setup). */
+    void (*init_preirq)(struct serial_port *);
+    void (*init_postirq)(struct serial_port *);
+    /* Hook to clean up after Xen bootstrap (before domain 0 runs). */
+    void (*endboot)(struct serial_port *);
+    /* Put a char onto the serial line. */
+    void (*putc)(struct serial_port *, char);
+    /* Get a char from the serial line: returns FALSE if no char available. */
+    int  (*getc)(struct serial_port *, char *);
 };
 
-/* 'Serial handles' are comprise the following fields. */
+/* 'Serial handles' are composed from the following fields. */
 #define SERHND_IDX      (1<<0) /* COM1 or COM2?                           */
 #define SERHND_HI       (1<<1) /* Mux/demux each transferred char by MSB. */
 #define SERHND_LO       (1<<2) /* Ditto, except that the MSB is cleared.  */
 #define SERHND_COOKED   (1<<3) /* Newline/carriage-return translation?    */
 
 /* Two-stage initialisation (before/after IRQ-subsystem initialisation). */
-void serial_init_stage1(void);
-void serial_init_stage2(void);
+void serial_init_preirq(void);
+void serial_init_postirq(void);
+
+/* Clean-up hook before domain 0 runs. */
+void serial_endboot(void);
 
 /* Takes a config string and creates a numeric handle on the COM port. */
-int parse_serial_handle(char *conf);
+int serial_parse_handle(char *conf);
 
 /* Transmit a single character via the specified COM port. */
-void serial_putc(int handle, unsigned char c);
+void serial_putc(int handle, char c);
 
 /* Transmit a NULL-terminated string via the specified COM port. */
 void serial_puts(int handle, const char *s);
@@ -108,15 +73,21 @@ void serial_puts(int handle, const char *s);
  * will not return until a character is available. It can safely be
  * called with interrupts disabled.
  */
-unsigned char serial_getc(int handle);
-/* 
- * Same as serial_getc but can also be called from interrupt handlers.
- */
-unsigned char irq_serial_getc(int handle);
+char serial_getc(int handle);
 
+/* Forcibly prevent serial lockup when the system is in a bad way. */
 void serial_force_unlock(int handle);
 
-void serial_endboot(void);
+/* Register a uart on serial port @idx (e.g., @idx==0 is COM1). */
+void serial_register_uart(int idx, struct uart_driver *driver, void *uart);
+
+/* Driver helper function: process receive work in interrupt context. */
+void serial_rx_interrupt(struct serial_port *port, struct cpu_user_regs *regs);
+
+/*
+ * Initialisers for individual uart drivers.
+ */
+void ns16550_init(void);
 
 #endif /* __XEN_SERIAL_H__ */